/*
 *	nextstep.m, copyright Paul A. Griffin 1995
 */

#import <appkit/appkit.h>
#import <sys/param.h>
#import <string.h>
#import "video.h"
#import "nextstep.h"

static id app, window, cview, controller;

static NXRect viewRect, windowRect;
static NXModalSession session;
static int pixelsHigh, pixelsWide, bytesPerRow;
static float videoRatio, scaleRatio;

void ExecuteDisplay(VidStream *vid_stream);
void InitDisplay(int w, int h);

@interface CWindow:Window 
{
} 
- showTitle:(int)dots :(const char *)filename; 
@end

@implementation CWindow
- showTitle:(int)dots :(const char *)filename; 
{	 
    unsigned char newname[MAXPATHLEN];
	
	strcpy(newname, filename);
	strcat(newname," "); 
	while(dots-- > 0) strcat(newname , ".");
	
	[self setTitleAsFilename:(const char *)newname];
	showSpeed = 1;
}
@end

@interface CView:View 
{
} 
- drawSelf:(const NXRect *)rects :(int)rectCount;
-(BOOL)acceptsFirstMouse; /*YES*/
- mouseDown:(NXEvent *)theEvent; /* left mouse */ 
- rightMouseDown:(NXEvent *)theEvent;
@end

@implementation CView
- drawSelf:(const NXRect *)rects :(int)rectCount
{
	int hf = holdFrame;
	static int first_time  = 1;
	
	[super drawSelf:rects :rectCount];

	if(curVidStream != NULL && !first_time) {
		drawFrame = 1;
		ExecuteDisplay(curVidStream);
		drawFrame = 0;
	}
	
	first_time = 0;
	
	return self;
}
- (BOOL)acceptsFirstMouse{
	return YES;
}

- mouseDown:(NXEvent *)theEvent
{
	unsigned char title[10]; 

	if(theEvent->flags & NX_ALPHASHIFTMASK){
		if(holdFrame == 1){
			loopFlag = loopFlag ? 0 : 1;
			/* display the loop status */	
			if(loopFlag) sprintf(title, "loop", frames_per_sec);
			else sprintf(title, "no loop", frames_per_sec);
			[window setTitle:(const char *)title];
		}
		else{
			doRewind = 1;
			holdFrame = 1;
		}
		return nil;
	}
	
	doRewind = holdFrame == 3 ? 1 : doRewind;
	
	holdFrame = holdFrame > 0 ? 0 : 2;	
	
	[window showTitle:(int)holdFrame :(const char *)filename];

	return nil;
}

- rightMouseDown:(NXEvent *)theEvent
{
	/* speed control */
	int k;
	unsigned char title[20]; 
	
	k = (theEvent->flags & NX_ALPHASHIFTMASK) ? -1 : 1;

	if(holdFrame == 0 || !showSpeed) frames_per_sec += k;
	if(frames_per_sec < 0) frames_per_sec = 0;
	showSpeed = 0;
	
	if(holdFrame > 0){	
		/* display the frames/sec in the title bar */	
		sprintf(title, "%d/sec", frames_per_sec); 
		[window setTitle:(const char *)title];
	}

	frame_interval = frames_per_sec>0 ? 1.0/(1.0*frames_per_sec) : 0.0001;

	return nil;
}
@end

@interface Controller:Object
{
}
- windowWillClose:sender;
- windowWillResize:sender toSize:(NXSize *)frameSize;
- windowDidResize:sender;
@end

@implementation Controller

- windowWillClose:sender
{
	/* window is about to close, so kill the program */
	int_handler();		
}
- windowWillResize:sender toSize:(NXSize *)frameSize;
{
	/* this override makes sure that the window resizing preserves
	 * the movie's aspect ratio, and is quantized in scale units of .1 
	 */
	 
	NXRect newRect;
	NXSize fill, new;
	unsigned char title[7];
	float ratio, scale;	
	
	
	
	fill.width = windowRect.size.width - viewRect.size.width;
	fill.height = windowRect.size.height - viewRect.size.height;
	
	new.width = frameSize->width - fill.width;
	new.height = frameSize->height - fill.height;
	 
	ratio = (float)new.width/(float)new.height;
	
	/* adjust aspect */
	if(ratio >= videoRatio){/* crank up the height */
		frameSize->height = fill.height + (float)new.width/videoRatio;
	}
	else if(ratio < videoRatio){/* crank up the width */	
		frameSize->width = fill.width + (float)new.height*videoRatio;
	}
	
	/* quantize size */
	scale = ((float)frameSize->width/(float)pixelsWide);
			
	if(scale-scaleRatio > 0.1) scaleRatio +=0.1;
	if(scale-scaleRatio < -0.1) scaleRatio -=0.1;
	
	ratio = scaleRatio/scale;
	new.width = ratio*(frameSize->width - fill.width);
	new.height = ratio*(frameSize->height - fill.height);
	frameSize->width = new.width+fill.width;	 
	frameSize->height = new.height+fill.height;	 
			
	/* display the scale in the title bar */	
	sprintf(title, "%3.1f", scaleRatio); 
	[window setTitle:(const char *)title];
	
}
- windowDidResize:sender
{
	[window getFrame:&windowRect];
	[cview getFrame:&viewRect];
    viewRect.origin.x = viewRect.origin.y = 0.0;

	[window showTitle:(int)holdFrame :(const char *)filename];

	return self;
}
	


@end

void InitDisplay(int w, int h)
{
    holdFrame = 1;
	drawFrame = 0;
	showSpeed = 1;
	doRewind  = 0;

	NXApp = [Application new];

    viewRect.origin.x = 8.0 * 64.0;
    viewRect.origin.y = 0.0; //512.0;

    pixelsHigh = h;
	pixelsWide = w;
	bytesPerRow = 4*16*((w +15)/16); 
	/* 16 comes from macroblock mb_width = (h_size + 15) / 16 */


	videoRatio = (float)w/(float)h;

	scaleRatio = 1.0;
	
	viewRect.size.width = (int)magFlag*w;
    viewRect.size.height = (int)magFlag*h;

    window = [[CWindow alloc] initContent:&viewRect style:NX_RESIZEBARSTYLE
        backing:NX_RETAINED buttonMask:NX_CLOSEBUTTONMASK defer:YES];
    [window setDepthLimit:NX_TwentyFourBitRGBDepth];
    [window useOptimizedDrawing:YES];
	
	[window showTitle:1 :(const char *)filename];

	[window setBackgroundGray:NX_BLACK];

	[NXApp beginModalSession:&session for:window];

    /* the movie's view */
    viewRect.origin.x = viewRect.origin.y = 0.0;
	cview = [[CView alloc] initFrame:&viewRect];	
	[cview setClipping:NO];
	[window setContentView:cview];	
	
	/* delegate (for button control) */
	controller = [[Controller alloc] init];	
	[window setDelegate:controller];

    [[window display] makeKeyAndOrderFront:nil];
	
	[NXApp runModalSession:&session];
	
	[window getFrame:&windowRect];
	[cview getFrame:&viewRect];
    viewRect.origin.x = viewRect.origin.y = 0.0;

}

void ExecuteDisplay(VidStream *vid_stream)
{
	/* process window server events */
	[NXApp runModalSession:&session];

	if(holdFrame < 4){ /* no end of file error */
		[window disableDisplay];
		[cview lockFocus];		    	
			NXDrawBitmap(&viewRect, pixelsWide, pixelsHigh,
        	8, 3, 32, bytesPerRow, NO, NO, NX_RGBColorSpace,
        	(const unsigned char *const*)&vid_stream->current->display);    	
			DPSFlush();
    	[cview unlockFocus];
		[window reenableDisplay];
	}
	else holdFrame =3;
	   
	if(frames_per_sec == 0 && holdFrame == 0) holdFrame = 1;

	if(holdFrame>0 || drawFrame == 1) 
		[window showTitle:(int)holdFrame :(const char *)filename];


	while(holdFrame>0 && !drawFrame && !doRewind) 
		[NXApp runModalSession:&session];


  totNumFrames++;
}

void TerminateDisplay()
{
    [window close];
}


